Ruby 日記 11日目: instance_evalとmodule_eval(class_eval)
次のプログラムは"Hello, world"と表示します。
同じ結果になる選択肢はどれですか(複数選択)
code:gold/ex11/main.rb
module M
CONST = "Hello, world"
def self.say
CONST
end
end
p M::say
選択肢&解説:
選択肢1
code:gold/ex11/choice01.rb
module M
CONST = "Hello, world"
end
module M
def self.say
CONST
end
end
p M::say
code:sh
# ruby gold/ex11/choice01.rb
"Hello, world"
お、エラーにならない。この辺の理解が曖昧だなぁ。
Mモジュールを別々に書いたとしてもCONSTを参照できるんだね。
選択肢2
code:gold/ex11/choice02.rb
module M
CONST = "Hello, world"
end
M.instance_eval(<<-CODE)
def say
CONST
end
CODE
p M::say
オブジェクトのコンテキストで文字列 expr またはオブジェクト自身をブロックパラメータとするブロックを 評価してその結果を返します。
オブジェクトのコンテキストで評価するとは評価中の self をそのオブジェクトにして実行するということです。 また、文字列 expr やブロック中でメソッドを定義すればそのオブジェクトの特異メソッドが定義されます。
code:sh
# ruby gold/ex11/choice02.rb
(eval):2:in `say': uninitialized constant Module::CONST (NameError)
from gold/ex11/choice02.rb:11:in `<main>'
エラーになる。sayメソッドの中で CONST を参照できてない状態だな。
模試の公式解説によると
instance_evalの引数に文字列を指定するとネストの状態はモジュールMの特異クラスになります。
CONSTはモジュールMにのみありますので、例外が発生します。
ってことなのだけど、「ネストの状態はモジュールMの特異クラスになります。」がよくわかってない。
code:singleton_class.rb
obj = Object.new # obj = nil でも可
class << obj
def test
:
end
:
end
クラス定義と同じ構文で特定のオブジェクトにメソッドやインスタンス変数を 定義/追加します。
この構文の内部で定義したメソッドや定数は指定した オブジェクトに対してだけ有効になります。
あ、こういうのを特異クラスっていうんだ
モジュールMの特異クラスから、モジュールMで定義された定数COSNTを参照することはできないんだね。
選択肢3
code:gold/ex11/choice03.rb
module M
CONST = "Hello, world"
end
class << M
def say
CONST
end
end
p M::say
これ、ほぼ選択肢2と同じじゃん?
code:sh
# ruby gold/ex11/choice03.rb
gold/ex11/choice03.rb:7:in `say': uninitialized constant Module::CONST (NameError)
from gold/ex11/choice03.rb:11:in `<main>'
そうよね。
選択肢4
code:gold/ex11/choice04.rb
module M
CONST = "Hello, world"
end
M.module_eval(<<-CODE)
def self.say
CONST
end
CODE
p M::say
モジュールのコンテキストで文字列 expr またはモジュール自身をブロックパラメータとするブロックを 評価してその結果を返します。
モジュールのコンテキストで評価するとは、実行中そのモジュールが self になるということです。
ふむふむ
つまり、そのモジュールの定義式の中にあるかのように実行されます。
お〜、ってことはよさそう
code:sh
# ruby gold/ex11/choice04.rb
"Hello, world"
以上より、正解は「選択肢1と選択肢4」だね〜
/icons/hr.icon
ちなみに、選択肢3と見た目が近いんだけど、
code:gold/ex11/sample.rb
module M
CONST = "Hello, world"
class << M
def say
CONST
end
end
end
p M::say
これはモジュールMの特異クラスが定義されたってことにはならなくて、モジュールM内で特異メソッドが定義されたよってことになるみたい。
code:sh
# ruby gold/ex11/sample.rb
"Hello, world"